package com.live.qn.stream;

import android.hardware.Camera;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.live.qn.stream.constants.QiniuStreamEventConstants;
import com.live.qn.stream.widget.CameraPreviewFrameView;
import com.qiniu.android.dns.DnsManager;
import com.qiniu.android.dns.IResolver;
import com.qiniu.android.dns.NetworkInfo;
import com.qiniu.android.dns.http.DnspodFree;
import com.qiniu.android.dns.local.AndroidDnsServer;
import com.qiniu.android.dns.local.Resolver;
import com.qiniu.pili.droid.streaming.AVCodecType;
import com.qiniu.pili.droid.streaming.AudioSourceCallback;
import com.qiniu.pili.droid.streaming.CameraStreamingSetting;
import com.qiniu.pili.droid.streaming.MediaStreamingManager;
import com.qiniu.pili.droid.streaming.StreamStatusCallback;
import com.qiniu.pili.droid.streaming.StreamingEnv;
import com.qiniu.pili.droid.streaming.StreamingProfile;
import com.qiniu.pili.droid.streaming.StreamingSessionListener;
import com.qiniu.pili.droid.streaming.StreamingState;
import com.qiniu.pili.droid.streaming.StreamingStateChangedListener;

import java.io.IOException;
import java.net.InetAddress;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;

public class QiniuStreamingViewManager extends SimpleViewManager<CameraPreviewFrameView> implements LifecycleEventListener, StreamingStateChangedListener, StreamingSessionListener, StreamStatusCallback, AudioSourceCallback {

    private ThemedReactContext context;
    private CameraPreviewFrameView cameraPreviewFrameView;
    private RCTEventEmitter mEventEmitter;
    private StreamingProfile mProfile;
    private MediaStreamingManager mMediaStreamingManager;

    private Boolean isStreaming = false;
    private Boolean isStreamReady = false;

    @Override
    public void onHostResume() {
        mMediaStreamingManager.resume();
    }

    @Override
    public void onHostPause() {
        mMediaStreamingManager.pause();
    }

    @Override
    public void onHostDestroy() {
        context.removeLifecycleEventListener(this);
        mMediaStreamingManager.destroy();
    }

    @NonNull
    @Override
    public String getName() {
        return "RCTQiniuStream";
    }

    @Override
    @Nullable
    public Map getExportedCustomDirectEventTypeConstants() {
        MapBuilder.Builder<String, Map<String, String>> builder = MapBuilder.builder();
        for (String event : QiniuStreamEventConstants.EVENT_LIST) {
            builder.put(event, MapBuilder.of("registrationName", event));
        }
        return builder.build();
    }

    @NonNull
    @Override
    protected CameraPreviewFrameView createViewInstance(@NonNull ThemedReactContext reactContext) {
        context = reactContext;
        // 注册生命周期
        context.addLifecycleEventListener(this);
        // 获取对应的json事件对象
        mEventEmitter = context.getJSModule(RCTEventEmitter.class);
        // 必须要初始化对应的环境
        StreamingEnv.init(context);
        // 初始化对应的推流视图
        initCameraPreviewFrameView();
        return cameraPreviewFrameView;
    }

    @Override
    public void onDropViewInstance(@NonNull CameraPreviewFrameView view) {
        super.onDropViewInstance(view);
        mMediaStreamingManager.destroy();
    }

    /**
     * 初始化配置
     */
    private void initCameraPreviewFrameView() {
        // 实例化对应的试图
        cameraPreviewFrameView = new CameraPreviewFrameView(context);
        cameraPreviewFrameView.setKeepScreenOn(true);

        // 编码设置
        mProfile = new StreamingProfile();
        mProfile
                .setVideoQuality(StreamingProfile.VIDEO_QUALITY_HIGH1)
                .setAudioQuality(StreamingProfile.AUDIO_QUALITY_MEDIUM2)
                .setEncodingSizeLevel(StreamingProfile.VIDEO_ENCODING_HEIGHT_480)
                .setEncoderRCMode(StreamingProfile.EncoderRCModes.QUALITY_PRIORITY)
                // 直播流状态回调时间触发
                .setStreamStatusConfig(new StreamingProfile.StreamStatusConfig(3))
                // 自适应码率
                .setBitrateAdjustMode(StreamingProfile.BitrateAdjustMode.Auto)
                .setDnsManager(getDnsManager());

        // 摄像头配置
        CameraStreamingSetting cameraSetting = new CameraStreamingSetting();
        cameraSetting
                // 自动对焦（Video）
                .setFocusMode(CameraStreamingSetting.FOCUS_MODE_CONTINUOUS_VIDEO)
                .setCameraId(Camera.CameraInfo.CAMERA_FACING_FRONT)
                .setContinuousFocusModeEnabled(true)
                .setCameraPrvSizeLevel(CameraStreamingSetting.PREVIEW_SIZE_LEVEL.MEDIUM)
                .setCameraPrvSizeRatio(CameraStreamingSetting.PREVIEW_SIZE_RATIO.RATIO_16_9);

        // 配置对应的
        //streaming engine init and setListener
        mMediaStreamingManager = new MediaStreamingManager(context, cameraPreviewFrameView, AVCodecType.SW_VIDEO_WITH_HW_AUDIO_CODEC);  // soft codec
        mMediaStreamingManager.prepare(cameraSetting, mProfile);
        mMediaStreamingManager.setStreamingStateListener(this);
        // Camera预览size监听
        mMediaStreamingManager.setStreamingSessionListener(this);
        mMediaStreamingManager.setStreamStatusCallback(this);
        mMediaStreamingManager.setAudioSourceCallback(this);
    }

    /**
     * 获取视图id
     *
     * @return int
     */
    private int getId() {
        return cameraPreviewFrameView.getId();
    }

    /**
     * 摄像头对应的流状态响应
     *
     * @param streamingState StreamingState
     * @param extra          Object
     */
    @Override
    public void onStateChanged(StreamingState streamingState, Object extra) {
        Log.e("七牛stream(状态更新)", "streamingState = " + streamingState + "extra = " + extra);
        switch (streamingState) {
            case PREPARING:
                Log.e("七牛stream(状态更新)", "预备中");
                mEventEmitter.receiveEvent(getId(), QiniuStreamEventConstants.ON_PREPARING, null);
                break;
            case READY:
                isStreamReady = true;
                Log.e("七牛stream(状态更新)", "准备好了");
                startStreaming();
                mEventEmitter.receiveEvent(getId(), QiniuStreamEventConstants.ON_READY, null);
                break;
            case CONNECTING:
                Log.e("七牛stream(状态更新)", "连接中");
                mEventEmitter.receiveEvent(getId(), QiniuStreamEventConstants.ON_CONNECTING, null);
                break;
            case STREAMING:
                Log.e("七牛stream(状态更新)", "推流中");
                mEventEmitter.receiveEvent(getId(), QiniuStreamEventConstants.ON_STREAMING, null);
                break;
            case SHUTDOWN:
                Log.e("七牛stream(状态更新)", "直播中断");
                mEventEmitter.receiveEvent(getId(), QiniuStreamEventConstants.ON_SHUTDOWN, null);
                break;
            case IOERROR:
                Log.e("七牛stream(状态更新)", "网络连接失败");
                mEventEmitter.receiveEvent(getId(), QiniuStreamEventConstants.ON_IO_ERROR, null);
                break;
            case OPEN_CAMERA_FAIL:
                Log.e("七牛stream(状态更新)", "摄像头打开失败");
                mEventEmitter.receiveEvent(getId(), QiniuStreamEventConstants.ON_OPEN_CAMERA_FAIL, null);
                break;
            case DISCONNECTED:
                Log.e("七牛stream(状态更新)", "已经断开连接");
                mEventEmitter.receiveEvent(getId(), QiniuStreamEventConstants.ON_DISCONNECTED, null);
                break;
            case TORCH_INFO:
                Log.e("七牛stream(状态更新)", "开启闪光灯");
                mEventEmitter.receiveEvent(getId(), QiniuStreamEventConstants.ON_TORCH_INFO, null);
                break;
        }
    }

    @Override
    public boolean onRecordAudioFailedHandled(int i) {
        return false;
    }

    @Override
    public boolean onRestartStreamingHandled(int i) {
        return false;
    }

    @Override
    public Camera.Size onPreviewSizeSelected(List<Camera.Size> list) {
        return null;
    }

    @Override
    public int onPreviewFpsSelected(List<int[]> list) {
        return 0;
    }

    @Override
    public void notifyStreamStatusChanged(StreamingProfile.StreamStatus streamStatus) {

    }

    @Override
    public void onAudioSourceAvailable(ByteBuffer byteBuffer, int i, long l, boolean b) {

    }

    /**
     * 防dns劫持配置七牛dns管理
     *
     * @return DnsManager
     */
    private static DnsManager getDnsManager() {
        IResolver r0 = new DnspodFree();
        IResolver r1 = AndroidDnsServer.defaultResolver();
        IResolver r2 = null;
        try {
            r2 = new Resolver(InetAddress.getByName("119.29.29.29"));
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return new DnsManager(NetworkInfo.normal, new IResolver[]{r0, r1, r2});
    }

    /**
     * 开始播放
     */
    private void startStreaming() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                if (mMediaStreamingManager != null) {
                    mMediaStreamingManager.startStreaming();
                }
            }
        }).start();
    }

    /**
     * 停止直播
     */
    private void stopStreaming() {
        mMediaStreamingManager.stopStreaming();
    }

    /**
     * 是否需要推送直播流的开关
     *
     * @param cameraPreviewFrameView CameraPreviewFrameView
     * @param status                 Boolean
     */
    @ReactProp(name = "publishStatus")
    public void setStreamPublishStatus(CameraPreviewFrameView cameraPreviewFrameView, @NonNull Boolean status) {
        if (isStreaming != status) {
            isStreaming = status;
        }
        // 当直播state回调已经可以开始时候
        if (isStreamReady) {
            if (status) {
                startStreaming();
            } else {
                stopStreaming();
            }
        }
    }

    /**
     * 配置对应的推流地址
     *
     * @param cameraPreviewFrameView CameraPreviewFrameView
     * @param url                    String
     */
    @ReactProp(name = "publishUrl")
    public void setPublishUrl(CameraPreviewFrameView cameraPreviewFrameView, @Nullable String url) {
        try {
            if (url != null) {
                mProfile.setPublishUrl(url);
            }
        } catch (URISyntaxException e) {
            Log.e("七牛stream(配置地址)", "推流地址错误");
        }
    }

    /**
     * 配置摄像头的前后
     *
     * @param cameraPreviewFrameView CameraPreviewFrameView
     * @param direction              int
     */
    @ReactProp(name = "direction")
    public void setCameraDirection(CameraPreviewFrameView cameraPreviewFrameView, int direction) {
        switch (direction) {
            case Camera.CameraInfo.CAMERA_FACING_FRONT:
                mMediaStreamingManager.switchCamera(CameraStreamingSetting.CAMERA_FACING_ID.CAMERA_FACING_FRONT);
                break;

            case Camera.CameraInfo.CAMERA_FACING_BACK:
                mMediaStreamingManager.switchCamera(CameraStreamingSetting.CAMERA_FACING_ID.CAMERA_FACING_BACK);
                break;
        }
    }
}
